package yi.Note.data.provider;

import android.net.Uri;
import android.provider.BaseColumns;
import android.content.ContentValues;
import android.content.ContentUris;
import android.database.Cursor;
import android.content.Context;
import android.os.Binder;

/**
 * Created with IntelliJ IDEA.
 * User: b251
 * Date: 13-12-7
 * Time: 下午7:57
 * To change this template use File | Settings | File Templates.
 */
public abstract class NoteContent {
    public static final int ID_ADD = -2;
    public static final int ID_NONE = -1;

    public static final String AUTHORITY = "yi.providers.note";
    public static final String TABLE_NOTE = "note";
    public static final String TABLE_ATT = "att";

    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.yi.note";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.yi.note";

    public static final String[] COUNT_COLUMNS = new String[]{"count(*)"};

    // Newly created objects get this id
    public static final int NOT_SAVED = -1;

    // The base Uri that this piece of content came from
    public Uri mBaseUri;
    // Lazily initialized uri for this Content
    private Uri mUri = null;
    // The id of the Content
    public long mId = NOT_SAVED;

    // Write the Content into a ContentValues container
    public abstract ContentValues toContentValues();
    // Read the Content from a ContentCursor
    public abstract void restore (Cursor cursor);

    // The Uri is lazily initialized
    public Uri getUri() {
        if (mUri == null) {
            mUri = ContentUris.withAppendedId(mBaseUri, mId);
        }
        return mUri;
    }

    public boolean isSaved() {
        return mId != NOT_SAVED;
    }
    public static <T extends NoteContent> T restoreContentWithId(Context context,
                                                                  Class<T> klass, Uri contentUri, String[] contentProjection, long id) {
        long token = Binder.clearCallingIdentity();
        Uri u = ContentUris.withAppendedId(contentUri, id);
        Cursor c = context.getContentResolver().query(u, contentProjection, null, null, null);
        if(c==null){
            return null;
        }
        try {
            if (c.moveToFirst()) {
                return getContent(c, klass);
            } else {
                return null;
            }
        } finally {
            c.close();
            Binder.restoreCallingIdentity(token);
        }
    }


    // The Content sub class must have a no-arg constructor
    static public <T extends NoteContent> T getContent(Cursor cursor, Class<T> klass) {
        try {
            T content = klass.newInstance();
            content.mId = cursor.getLong(0);
            content.restore(cursor);
            return content;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Uri save(Context context) {
        if (isSaved()) {
            throw new UnsupportedOperationException();
        }
        Uri res = context.getContentResolver().insert(mBaseUri, toContentValues());
        mId = Long.parseLong(res.getPathSegments().get(1));
        return res;
    }

    public int update(Context context, ContentValues contentValues) {
        if (!isSaved()) {
            throw new UnsupportedOperationException();
        }
        return context.getContentResolver().update(getUri(), contentValues, null, null);
    }

    static public int update(Context context, Uri baseUri, long id, ContentValues contentValues) {
        return context.getContentResolver()
                .update(ContentUris.withAppendedId(baseUri, id), contentValues, null, null);
    }

    static public int delete(Context context, Uri baseUri, long id) {
        return context.getContentResolver()
                .delete(ContentUris.withAppendedId(baseUri, id), null, null);
    }

    /**
     * Generic count method that can be used for any ContentProvider
     *
     * @param context the calling Context
     * @param uri the Uri for the provider query
     * @param selection as with a query call
     * @param selectionArgs as with a query call
     * @return the number of items matching the query (or zero)
     */
    static public int count(Context context, Uri uri, String selection, String[] selectionArgs) {
        Cursor cursor = context.getContentResolver().query(uri, COUNT_COLUMNS, selection, selectionArgs, null);
        if(cursor==null) return 0;

        try{
            if(cursor.moveToFirst()){
                return cursor.getInt(0);
            }
        } finally {
            cursor.close();
        }
        return 0;
    }

    /**
     * Same as {@link #count(Context, Uri, String, String[])} without selection.
     */
    static public int count(Context context, Uri uri) {
        return count(context, uri, null, null);
    }

    static public Uri uriWithLimit(Uri uri, int limit) {
        return uri.buildUpon().appendQueryParameter("limit", Integer.toString(limit)).build();
    }

    protected NoteContent(){}

    public static final class Note extends  NoteContent implements BaseColumns{
        public static final String CONTENT_DIR = "note";
        public static final Uri CONTENT_URI = Uri.parse("content://" +AUTHORITY + "/" + CONTENT_DIR);
        public static final Uri CONTENT_CLEAR_URI = Uri.parse("content://" +AUTHORITY + "/" + CONTENT_DIR + "/clear");

        public static final String TITLE = "title";
        public static final String TEXT = "text";
        public static final String TIMESTAMP = "time";
        public static final String REMINDER = "reminder";

        public static final String[] SELECT_PROJECTIONS = new String[]{
            _ID,TITLE,TEXT,TIMESTAMP, REMINDER
        };

        public long mId;
        public String mTitle;
        public String mText;
        public long mTimestamp;
        public long mReminder;

        public Note(){
            mBaseUri = CONTENT_URI;
        }

        @Override
        public ContentValues toContentValues() {
            ContentValues cv = new ContentValues();
            cv.put(TITLE, mTitle);
            cv.put(TEXT, mText);
            cv.put(TIMESTAMP, mTimestamp);
            cv.put(REMINDER, mReminder);
            return cv;
        }

        @Override
        public void restore(Cursor cursor) {
            mBaseUri = CONTENT_URI;
            mId = cursor.getLong(cursor.getColumnIndex(_ID));
            mTitle = cursor.getString(cursor.getColumnIndex(TITLE));
            mText = cursor.getString(cursor.getColumnIndex(TEXT));
            mTimestamp = cursor.getLong(cursor.getColumnIndex(TIMESTAMP));
            mReminder = cursor.getLong(cursor.getColumnIndex(REMINDER));
        }
    }

    public static final class Attachment extends NoteContent implements BaseColumns{
        public static final String CONTENT_DIR = "att";
        public static final Uri CONTENT_URI = Uri.parse("content://" +AUTHORITY + "/" + CONTENT_DIR);
        public static final Uri CONTENT_LIST_BY_NOTE_URI = Uri.parse("content://" +AUTHORITY + "/" + CONTENT_DIR +"/note");

        public static final String NOTE_ID = "note_id";
        public static final String TYPE = "type";
        public static final String URI = "uri";
        public static final String SIZE = "size";

        public static final String[] SELECT_PROJECTIONS = new String[]{
                _ID,NOTE_ID,TYPE,URI,SIZE
        };

        public static final int PIC = 0;
        public static final int AUDIO = 1;
        public static final int VIDEO = 2;
        public static final int OTHER = 3;

        public long mNoteId;
        public String mMimeType;
        public String mAttUri;
        public int mSize;

        public Attachment(){
            mBaseUri = CONTENT_URI;
        }

        @Override
        public ContentValues toContentValues() {
            ContentValues cv = new ContentValues();
            cv.put(NOTE_ID, mNoteId);
            cv.put(TYPE, mMimeType);
            cv.put(URI, mAttUri);
            cv.put(SIZE, mSize);
            return cv;
        }

        @Override
        public void restore(Cursor cursor) {
            mBaseUri = CONTENT_URI;
            mId = cursor.getLong(cursor.getColumnIndex(_ID));
            mNoteId = cursor.getLong(cursor.getColumnIndex(NOTE_ID));
            mMimeType = cursor.getString(cursor.getColumnIndex(TYPE));
            mAttUri = cursor.getString(cursor.getColumnIndex(URI));
            mSize = cursor.getInt(cursor.getColumnIndex(SIZE));
        }

        public static Attachment[] restoreAttWithNoteId(Context context, long noteId){
            Cursor cursor = context.getContentResolver().query(CONTENT_LIST_BY_NOTE_URI, SELECT_PROJECTIONS, null, null,null);
            if(cursor==null) return new Attachment[0];

            try{
                int count = cursor.getCount();
                Attachment[] ret = new Attachment[count];
                for(int i=0; i<count; i++){
                    cursor.moveToNext();
                    Attachment a = new Attachment();
                    a.restore(cursor);
                    ret[i] = a;
                }
                return ret;
            }finally {
                cursor.close();
            }
        }
    }
}
